{"cells":[{"attachments":{},"cell_type":"markdown","metadata":{"id":"11n5gndbRzoY"},"source":["# Files and Exceptions\n"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"AIFsv_RZ1iV0"},"source":["
\n","
\n"," \n","
\n","
\n"," \n","
\n","
"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"wJjIP5Vne7cM"},"source":["Now that you've mastered the basic skills you need to write organized programs that are easy to use, it’s time to think about making your programs even more relevant and usable."]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"SwFKFBMwRzoa"},"source":["## Reading from a File"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"xtOzCNTJcj3N"},"source":["An incredible amount of data is available in text files. Text files can contain weather data, traffic data, socioeconomic data, literary works, and more. Reading from a file is particularly useful in data analysis applications, but it’s also applicable to any situation in which you want to analyze or modify information stored in a file."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Reading the Contents of a File"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["To begin, we need a file with a few lines of text in it. Let’s start with a file that contains `pi` to 30 decimal places:"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":4,"status":"ok","timestamp":1668686223113,"user":{"displayName":"phonchi chung","userId":"13517391734500420886"},"user_tz":-480},"id":"ossL66xxcoGg","outputId":"6fac1a14-1607-409b-c6f1-0b05188f6e2c"},"outputs":[],"source":["%%writefile pi_digits.txt\n","3.1415926535\n"," 8979323846\n"," 2643383279"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"Ss9hRGHDRzob"},"source":["Here’s a program that opens this file, reads it, and prints the contents of the file to the screen:"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["3.1415926535\n"," 8979323846\n"," 2643383279\n","\n"]}],"source":["file_object = open('pi_digits.txt')\n","print(file_object.read())\n","file_object.close()"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"TVuZi_rfsC9u"},"source":["To do any work with a file, even just printing its contents, you first need to open the file to access it. The `open()` function needs one argument: the name of the file you want to open. Python looks for this file in the directory where the program that’s currently being executed is stored. The `open()` function returns an object representing the file. Here, `open('pi_digits.txt')` returns an object representing `pi_digits.txt`. Python assigns this object to `file_object`, which we’ll work with later in the program."]},{"cell_type":"code","execution_count":2,"metadata":{"id":"4X-QB57Sqxbu"},"outputs":[{"name":"stdout","output_type":"stream","text":["3.1415926535\n"," 8979323846\n"," 2643383279\n"]}],"source":["# A recommended way:\n","with open('pi_digits.txt') as file_object: # file_object = open('pi_digits.txt')\n"," contents = file_object.read() # We do not have to call file_object.close()\n","print(contents.strip())"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The keyword `with` closes the file once access to it is no longer needed. Notice how we call `open()` in this program but not `close()`. You could open and close the file by calling `open()` and `close()`, but if a bug in your program \n","prevents the `close()` method from being executed, the file may never close! This may seem trivial, but improperly closed files can cause data to be lost or corrupted. \n","\n","Once we have a file object representing `pi_digits.txt`, we use the `read()` method in the second line of our program to read the entire contents of the file and store it as one long string in `contents`. Since `read()` returns an empty string when it reaches the end of the file; this empty string shows up as a blank line. If you want to remove the extra blank line, you can use `strip()` in the call to `print()`.\n","\n","> It’s not always easy to know exactly when you should close a file, but with the structure shown here, Python will figure \n","that out for you. All you have to do is open the file and work with it as desired, trusting that Python will close it \n","automatically when the `with` block finishes execution. "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### File Paths"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Sometimes, depending on how you organize your work, the file you want to open won't be in the same directory as your program file. To get Python to open files from a directory other than the one where your program file is stored, you need to provide a file path , which tells Python to look in a specific location on your system. A ***relative file path*** will tell Python to look for a given location relative to the directory where the currently running program file is stored. For example, you’d write:\n","\n","```python\n","with open('text_files/filename.txt') as file_object:\n","```\n","\n","This line tells Python to look for the desired .txt file in the folder `text_files` and assumes that `text_files` is located in the current directory.\n","\n","> Windows systems use a backslash (`\\`) instead of a forward slash (`/`) when displaying file paths, but you can still use forward slashes in your code."]},{"cell_type":"code","execution_count":3,"metadata":{},"outputs":[],"source":["!mkdir text_files"]},{"cell_type":"code","execution_count":4,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["Writing text_files/pi_digits2.txt\n"]}],"source":["%%writefile text_files/pi_digits2.txt\n","3.1415926535\n"," 8979323846\n"," 2643383279"]},{"cell_type":"code","execution_count":8,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["3.1415926535\n"," 8979323846\n"," 2643383279\n"]}],"source":["with open('text_files/pi_digits2.txt') as file_object:\n"," contents = file_object.read()\n","print(contents.strip())"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["You can also tell Python exactly where the file is on your computer regardless of where the program that’s being executed is stored. This is called an ***absolute file path***. Absolute paths are usually longer than relative paths, so it’s helpful to assign them to a variable and then pass that variable to `open()`:\n","\n","```python\n","file_path = '/home/phonchi/other_files/text_files/filename.txt'\n","with open(file_path) as file_object:\n","```"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Reading Line by Line"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["When you're reading a file, you'll often want to examine each line of the file. You might be looking for certain information in the file, or you might want to modify the text in the file in some way. You can use a `for` loop on the file object to examine each line from a file one at a time:"]},{"cell_type":"code","execution_count":10,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["3.1415926535\n","8979323846\n","2643383279\n"]}],"source":["filename = 'pi_digits.txt'\n","with open(filename) as file_object: # file_object is also iterable!\n"," for line in file_object:\n"," print(line.strip())"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["To examine the file's contents, we work through each line in the file by looping over the file object. Since there is a newline in each line of file and the print function adds its own newline each time we call it, so we will end up with two newline characters at the end of each line: one from the file and one from `print()`. Using `strip()` on each line in the `print()` call eliminates these extra blank lines."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Making a List of Lines from a File"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["When you use `with`, **the file object returned by `open()` is only available inside the with block that contains it**. If you want to retain access to a file's contents outside the `with` block, you can store the file's lines in a `list` inside the block and then work with that `list`!"]},{"cell_type":"code","execution_count":11,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["['3.1415926535\\n', ' 8979323846\\n', ' 2643383279\\n']\n","3.141592653589793238462643383279\n","32\n"]}],"source":["filename = 'pi_digits.txt'\n","with open(filename) as file_object:\n"," lines = file_object.readlines()\n","\n","print(lines) # List of strings\n","pi_string = ''\n","for line in lines:\n"," pi_string += line.strip()\n"," \n","print(pi_string)\n","print(len(pi_string)) # The string is 32 characters long because it also includes the leading 3 and a decimal point"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The `readlines()` method takes each line from the file and stores it in a list. This list is then assigned to `lines`, which we can continue to work with after the `with` block ends. Here, we create a variable, `pi_string`, to hold the digits of pi. We then create a loop that adds each line of digits to `pi_string` and removes the newline character from each line."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["> When Python reads from a text file, it interprets all text in the file as a `string`. If you read in a number and want to work with that value in a numerical context, you’ll have to convert it to an integer using the `int()` function or convert it to a float using the `float()` function."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Writing to a File"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["One of the simplest ways to save data is to write it to a file. When you write text to a file, the output will still be available after you close the terminal containing your program’s output. You can examine output after a program \n","finishes running, and you can share the output files with others as well. You can also write programs that read the text back into memory and work with it again later!"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### Writing to an Empty File"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["To write text to a file, you need to call `open()` with a second argument telling Python that you want to write to the file"]},{"cell_type":"code","execution_count":8,"metadata":{},"outputs":[],"source":["filename = 'programming.txt'\n","\n","with open(filename, 'w') as file_object:\n"," file_object.write(\"We love programming!\")"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The call to `open()` in this example has two arguments. The first argument is still the name of the file we want to open. The second argument, 'w', tells Python that we want to open the file in write mode. You can open a file in read mode ('r'), write mode ('w'), append mode ('a'), or a mode that allows you to read and write to the file ( 'r+'). If you omit the mode argument, Python opens the file in read-only mode by default. Here, we use the `write()` method on the file object to write a string to the file."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["> Python can only write strings to a text file. If you want to store numerical data in a text file, you'll have to convert the \n","data to string format first using the `str()` function."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["\n","> The `open()` function automatically creates the file you're writing to if it doesn't already exist. However, be careful opening a file in write mode ('w') because if the file does exist, Python will erase the contents of the file before returning the file object."]},{"cell_type":"code","execution_count":7,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["12\n"]}],"source":["with open(filename, 'w') as file_object:\n"," print(\"12\")"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["While reading through a file, the system maintains a ***file-position pointer***(index) representing the location of the next character to read. Therefore, the following code snippet will allow you to append it to the end of the file. "]},{"cell_type":"code","execution_count":9,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["20\n","20\n"]}],"source":["year = 2023\n","\n","with open(filename, 'r+') as file_object:\n"," spam = file_object.readlines()\n"," print(file_object.tell())\n"," print(len(\"We love programming!\"))\n"," file_object.write(str(year))"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The `tell()` function will return the current position of the file-position pointer. We can also use `seek()` to change the position. Checkout more details about file-position pointer [here](https://pynative.com/python-file-seek/)."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Appending to a File"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["If you want to add content to a file instead of writing over existing content, you can also open the file in append mode. When you open a file in append mode, Python doesn’t erase the contents of the file before returning the file object. \n","Any lines you write to the file will be added at the end of the file. If the file doesn’t exist yet, Python will create an empty file for you. "]},{"cell_type":"code","execution_count":10,"metadata":{},"outputs":[],"source":["filename = 'programming.txt'\n","\n","with open(filename, 'a') as file_object:\n"," file_object.write(\"\\nWe also love finding meaning in large datasets.\\n\")\n"," file_object.write(\"We love creating apps that can run in a browser.\\n\")"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The `write()` function doesn’t add any newlines to the text you write. So we need to add newline characters if we would like to. There is also a `writelines()` function that can write list of strings into files."]},{"cell_type":"markdown","metadata":{},"source":["## Storing Data"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Many of your programs will ask users to input certain kinds of information. You might allow users to store preferences in a game or provide data for visualization. Whatever the focus of your program is, you'll store the information users provide in data structures such as `lists` and `dictionaries`. When users close a program, you'll almost always want to save the information they entered. A simple way to do this involves storing your data using the `json` module."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The `json` module allows you to dump simple Python data structures into a file and load the data from that file the next time the program runs. **You can also use `json` to share data between different programming languages. It’s a useful and portable format.**"]},{"cell_type":"markdown","metadata":{},"source":["#### Using `json.dump()` and `json.load()`"]},{"cell_type":"markdown","metadata":{},"source":["The `json.dump()` function takes two arguments: a piece of data to store and a file object it can use to store the data."]},{"cell_type":"code","execution_count":11,"metadata":{},"outputs":[],"source":["import json\n","\n","numbers = [2, 3, 5, 7, 11, 13]\n","filename = 'numbers.json'\n","\n","with open(filename, 'w') as f:\n"," json.dump(numbers, f)"]},{"cell_type":"markdown","metadata":{},"source":["Now we’ll write a program that uses `json.load()` to read the list back into memory"]},{"cell_type":"code","execution_count":12,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["[2, 3, 5, 7, 11, 13]\n"]}],"source":["filename = 'numbers.json'\n","with open(filename) as f:\n"," numbers = json.load(f)\n"," \n","print(numbers)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["## Exceptions"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Python uses special objects called exceptions to manage errors that arise during a program's execution. Whenever an error makes Python unsure of what to do next, it creates an `exception` object. If we write code that handles the exception, the program will continue running. If you don't handle the exception, the program will halt and show a ***traceback***, which includes a report of the exception that was raised."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Exceptions are handled with `try-except` blocks. A `try-except` block tells Python what to do if an exception is raised. When we use `try-except` blocks, our programs will continue running even if things go wrong. Instead of tracebacks, which can be confusing for users to read, users will see friendly error messages that we write!"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Handling the `ZeroDivisionError` Exception"]},{"cell_type":"code","execution_count":13,"metadata":{},"outputs":[{"ename":"ZeroDivisionError","evalue":"division by zero","output_type":"error","traceback":["\u001b[1;31m---------------------------------------------------------------------------\u001b[0m","\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)","\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_19556\\1152173066.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[1;31mZeroDivisionError\u001b[0m: division by zero"]}],"source":["print(5/0)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The error reported at the first line in the traceback, `ZeroDivisionError`, is an exception object. Python creates this kind of object in response to a situation where it can't do what we ask. When this happens, Python stops the program and tells us the kind of exception that was raised. We can use this information to modify our program."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["When we think an error may occur, you can write a `try-except` block to handle the exception that might be raised. We tell Python to try running some code and tell it what to do if the code results in a particular kind of exception."]},{"cell_type":"code","execution_count":14,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["You can't divide by zero!\n"]}],"source":["try:\n"," print(5/0)\n","except ZeroDivisionError:\n"," print(\"You can't divide by zero!\")"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["We put `print(5/0)`, the line that caused the error, inside a `try` block. If the code in a `try` block works, Python skips over the `except` block. If the code in the `try` block causes an error, Python looks for an `except` block whose error matches the one that was raised and ran the code in that block. In this example, the user sees a friendly error message instead of a traceback."]},{"cell_type":"code","execution_count":15,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["Exceptions occur!\n"]}],"source":["try:\n"," print(5/0)\n","except:\n"," print(\"Exceptions occur!\")"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["If you do not add any exception type, it will capture all exceptions!"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Using Exceptions to Prevent Crashes"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Handling errors correctly is especially important when the program has more work to do after the error occurs. Let’s create a simple calculator that does only division:"]},{"cell_type":"code","execution_count":16,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["Overwriting division_calculator.py\n"]}],"source":["%%writefile division_calculator.py\n","print(\"Give me two numbers, and I'll divide them.\")\n","print(\"Enter 'q' to quit.\")\n","\n","while True:\n"," first_number = input(\"\\nFirst number: \")\n"," if first_number == 'q':\n"," break\n"," second_number = input(\"Second number: \")\n"," if second_number == 'q':\n"," break\n"," try:\n"," answer = int(first_number) / int(second_number)\n"," except ZeroDivisionError:\n"," print(\"You can't divide by 0!\")\n"," else: # Only executed if try block is succeed\n"," print(answer)\n"," finally: # Always executed\n"," print(\"\\nGive me two numbers, and I'll divide them.\")\n"," print(\"Enter 'q' to quit.\")"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Here, the error may occur on the line that performs the division, so that's where we'll put the `try-except` block. This example also includes an `else` block. Any code that depends on the `try` block executing successfully goes into the `else` block. In addition, the `finally` clause is guaranteed to execute, regardless of whether its `try` suite executes successfully or an exception occurs.\n","\n","We ask Python to try to complete the division operation in a `try` block, which includes only the code that might cause an error. The program continues to run, and the user never sees a traceback."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Handling the `FileNotFoundError` Exception"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["One common issue when working with files is handling missing files. The file you’re looking for might be in a different location, the filename may be misspelled, or the file may not exist at all"]},{"cell_type":"code","execution_count":20,"metadata":{},"outputs":[{"ename":"FileNotFoundError","evalue":"[Errno 2] No such file or directory: 'alice.txt'","output_type":"error","traceback":["\u001b[1;31m---------------------------------------------------------------------------\u001b[0m","\u001b[1;31mFileNotFoundError\u001b[0m Traceback (most recent call last)","\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_19556\\1385916738.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mfilename\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m'alice.txt'\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mf\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;31m# Note it is in read mode\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[0mcontents\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n","\u001b[1;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'alice.txt'"]}],"source":["filename = 'alice.txt'\n","with open(filename) as f: # Note it is in read mode\n"," contents = f.read()"]},{"cell_type":"code","execution_count":21,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["Sorry, the file alice.txt does not exist.\n"]}],"source":["filename = 'alice.txt'\n","try:\n"," with open(filename) as f:\n"," contents = f.read()\n","except FileNotFoundError:\n"," print(f\"Sorry, the file {filename} does not exist.\")"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["In this example, the code in the `try` block produces a `FileNotFoundError`, so Python looks for an `except` block that matches that error. Python then runs the code in that block, and the result is a friendly error message instead of a traceback."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Exercise 1: Assuming we are designing a word game called \"The Mysterious Island\" and we need to load the statistics of the player and enemies each time the game begins. Try to complete the following functions `load_data()` and `save_data()` so that you can load the JSON file if it does not exist using the exception handling techniques you just learned.\n","\n","\n","
"]},{"cell_type":"code","execution_count":22,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["You encounter a Slime with 10 HP!\n","You deal 7 damage to the Slime!\n","The Slime deals 2 damage to you!\n","Invalid choice! Try again.\n","You deal 9 damage to the Slime!\n","You defeated the Slime!\n","You encounter a Goblin with 25 HP!\n","You deal 6 damage to the Goblin!\n","The Goblin deals 8 damage to you!\n","You deal 7 damage to the Goblin!\n","The Goblin deals 5 damage to you!\n","You deal 7 damage to the Goblin!\n","The Goblin deals 4 damage to you!\n","You deal 10 damage to the Goblin!\n","You defeated the Goblin!\n","You encounter a Dragon with 80 HP!\n","You failed to escape!\n","The Dragon deals 13 damage to you!\n","You failed to escape!\n","The Dragon deals 9 damage to you!\n","You failed to escape!\n","The Dragon deals 15 damage to you!\n","You were defeated!\n","Game over!\n"]}],"source":["import random\n","import time\n","\n","def slow_print(text, delay=0.05):\n"," for char in text:\n"," print(char, end='', flush=True)\n"," time.sleep(delay)\n"," print()\n","\n","def battle(player, enemy):\n"," slow_print(f\"You encounter a {enemy['name']} with {enemy['hp']} HP!\")\n"," while player['hp'] > 0 and enemy['hp'] > 0:\n"," choice = input(\"Do you want to attack or escape? (a/e): \")\n"," if choice.lower() == 'a':\n"," player_damage = max(random.randint(player['attack']//2, player['attack']), 1)\n"," enemy_damage = max(random.randint(enemy['attack']//2, enemy['attack']), 1)\n"," slow_print(f\"You deal {player_damage} damage to the {enemy['name']}!\")\n"," enemy['hp'] -= player_damage\n"," if enemy['hp'] <= 0:\n"," break\n"," slow_print(f\"The {enemy['name']} deals {enemy_damage} damage to you!\")\n"," player['hp'] -= enemy_damage\n"," elif choice.lower() == 'e':\n"," escape_chance = random.randint(1, 10)\n"," if escape_chance <= 2:\n"," slow_print(\"You successfully escape from the battle!\")\n"," return\n"," else:\n"," slow_print(\"You failed to escape!\")\n"," enemy_damage = max(random.randint(enemy['attack']//2, enemy['attack']), 1)\n"," slow_print(f\"The {enemy['name']} deals {enemy_damage} damage to you!\")\n"," player['hp'] -= enemy_damage\n"," else:\n"," slow_print(\"Invalid choice! Try again.\")\n"," if player['hp'] <= 0:\n"," slow_print(\"You were defeated!\")\n"," print(\"Game over!\")\n"," return False\n"," else:\n"," slow_print(f\"You defeated the {enemy['name']}!\")\n","\n","def load_data():\n"," # Perform exception handling, if this is the first time you load the game\n"," _____:\n"," with open('game_data.json', 'r') as f:\n"," data = ____________________ # Read the data here using load()\n"," __________________________:\n"," data = {\n"," \"player\": {\n"," \"name\": \"Player\",\n"," \"hp\": 50,\n"," \"attack\": 10\n"," },\n"," \"enemies\": [\n"," {\n"," \"name\": \"Slime\",\n"," \"hp\": 10,\n"," \"attack\": 5\n"," },\n"," {\n"," \"name\": \"Goblin\",\n"," \"hp\": 25,\n"," \"attack\": 8\n"," },\n"," {\n"," \"name\": \"Dragon\",\n"," \"hp\": 80,\n"," \"attack\": 15\n"," }\n"," ]\n"," }\n"," save_data(data)\n"," return data\n","\n","def save_data(data):\n"," with open('game_data.json', 'w') as f:\n"," ______________# Save the data so that you can play again using dump()\n","\n","data = load_data()\n","player = data['player']\n","enemies = data['enemies']\n","flag = True\n","\n","for enemy in enemies:\n"," flag = battle(player, enemy)\n","\n","if flag != False: \n"," print(\"Congratulations!\")"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["In this chapter, you learned how to work with files. You learned to read an entire file at once and read through a file’s contents one line at a time. You learned to write to a file and append text onto the end of a file. You learned how to store Python data structures so you can save information your users provide, preventing them from having to start over each time they run a program. Finally, You read about exceptions and how to handle the exceptions you’re likely to see in your programs. "]}],"metadata":{"colab":{"collapsed_sections":["SwFKFBMwRzoa","n3ezAAdIsgpj","gASYx5-Cxzyg","2kLRVhae3rSa","DPpfFEA07W0A","uloOTsPL9A74","MTJO4K049nuU","3hD9uBt6AW9l","IvviPig3At12","HQK5zGP749m3","7YVyJ-IgBZ7s","L5VlI3VKg_dV","wgqoOGqEiUre","jscaE3K65HP9","UMo588t4rY-O","AGs4jgnSsZa1"],"provenance":[],"toc_visible":true},"kernelspec":{"display_name":"base","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.9.13"},"vscode":{"interpreter":{"hash":"1561eddc5e0c9c74df968f74d5080d02882967127f956e6e7049c43d2ef42321"}}},"nbformat":4,"nbformat_minor":0}